Exécution sécurisée des outils externes avec GSubprocess #39
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Exécution sécurisée des outils externes avec GSubprocess
Statut
À faire
Priorité
Haute
Objectif
Créer une abstraction C centralisée permettant à Labfy Investigation d’exécuter un outil externe de manière contrôlée avec
GSubprocess, sans passer par un shell.Le module devra :
stdoutetstderr;GCancellable;BackgroundTask.Contexte
Le ticket #036 fournit désormais un registre capable de détecter les outils présents sur la machine et de mémoriser leur chemin.
Le prochain besoin est d’exécuter ces outils sans introduire de vulnérabilité liée à une commande shell.
Labfy Investigation devra progressivement lancer des outils tels que :
Les arguments pourront contenir :
Ces valeurs ne doivent jamais être concaténées dans une commande textuelle.
Principe de sécurité
Le module doit lancer l’exécutable et ses arguments sous forme de tableau.
Exemple conceptuel correct :
Exemple interdit :
Les API suivantes sont interdites dans le code de production :
Le module doit utiliser
GSubprocessouGSubprocessLauncheravec un vecteur d’arguments.Périmètre
Ce ticket doit fournir :
tool_process;ToolProcessResult;stdout;stderr;Makefile.Hors périmètre
Ce ticket ne doit pas encore :
dig,curl,opensslou d’un autre outil ;L’intégration avec
BackgroundTasksera effectuée après validation de cette abstraction.Fichiers attendus
Le
Makefiledevra compiler le module dans l’application principale et fournir une cible :Contraintes générales
Modèle public
ToolProcessResult
La structure doit rester opaque.
Elle doit contenir au minimum :
Propriété
Le résultat retourné appartient à l’appelant.
Il doit être libéré avec :
Les sorties doivent être conservées avec
GBytes.Domaine d’erreur
Créer :
Énumération minimale :
Fonction :
Règle importante
Un programme qui se lance correctement puis retourne :
ne constitue pas une erreur de l’API.
Dans ce cas :
et le code de sortie est conservé dans
ToolProcessResult.La fonction ne retourne
FALSEque lorsque le module n’a pas pu mener l’exécution jusqu’à l’obtention d’un résultat exploitable.API publique attendue
L’API exacte peut être ajustée si une meilleure conception est justifiée, mais elle doit couvrir les opérations suivantes.
Exécution
Paramètres
executable_path
Chemin de l’exécutable.
Le module doit accepter un chemin absolu détecté par
ToolRegistry.Le chemin doit être :
NULL;Le module ne doit pas reconstruire une commande textuelle.
arguments
Tableau terminé par
NULL.Ce tableau contient uniquement les arguments placés après
argv[0].Exemple :
argumentspeut êtreNULL, ce qui signifie aucun argument supplémentaire.Le module doit construire en interne un vecteur de ce type :
Chaque argument doit rester un élément distinct.
working_directory
Dossier de travail facultatif.
NULLsignifie utiliser le dossier courant hérité ;Utiliser
GSubprocessLauncherlorsqu’un dossier de travail est fourni.cancellable
Objet d’annulation facultatif.
NULLsignifie que l’appel n’est pas annulable ;TOOL_PROCESS_ERROR_CANCELLED.out_result
Doit être non
NULL.Avant l’appel :
En cas de succès :
En cas d’échec :
error
Respecter la convention GLib :
Utilisation de GSubprocess
Créer le processus avec les drapeaux :
La capture recommandée est :
Cette API permet de récupérer des
GByteset évite de supposer que les sorties sont valides en UTF-8.Le module ne doit pas utiliser exclusivement :
car une sortie brute peut contenir des octets non UTF-8.
Données envoyées à stdin
Dans ce ticket, aucun contenu n’est envoyé à l’entrée standard.
La communication doit transmettre :
Une gestion explicite de stdin pourra être ajoutée plus tard.
Construction du vecteur d’arguments
L’implémentation peut utiliser :
Exemple conceptuel :
Le module doit décider clairement s’il duplique les chaînes ou s’il les emprunte uniquement pendant l’appel.
Comme
g_subprocess_launcher_spawnv()consomme le tableau pendant l’appel de création, les chaînes peuvent être empruntées si leur durée de vie couvre cet appel.Aucune fonction ne doit concaténer les arguments.
Résultat d’exécution
Cycle de vie
La fonction doit accepter
NULL.Sortie standard
Retourne une nouvelle référence.
L’appelant doit la libérer avec :
Sortie d’erreur
Retourne une nouvelle référence.
Fin normale
Code de sortie
Règles recommandées :
-1si le résultat estNULLou si le processus ne s’est pas terminé normalement.Terminaison par signal
Règles recommandées :
0dans les autres cas.Succès fonctionnel
Ajouter une fonction pratique :
Elle retourne
TRUEuniquement lorsque :Cette fonction ne doit pas confondre le succès de l’API et le succès du programme lancé.
Gestion des sorties vides
Même lorsqu’un programme n’écrit rien, le résultat doit rester exploitable.
Les choix acceptables sont :
ou :
La solution recommandée est de conserver un
GBytesvide afin de simplifier les appelants.Les deux flux doivent être indépendants.
Gestion de l’annulation
Lorsqu’un
GCancellableest annulé pendant :le module doit :
GSubprocessselon le comportement GLib ;FALSE;Le module ne doit pas laisser de processus enfant actif après l’annulation.
Nettoyage obligatoire
Tous les chemins d’erreur doivent libérer :
GSubprocessLauncher;GSubprocess;GBytestemporaires ;L’implémentation doit utiliser lorsque cela améliore la lisibilité :
Le style doit rester cohérent avec le reste du projet.
Comportement attendu
Exécutable introuvable
Exécutable valide, code zéro
Exécutable valide, code non nul
Annulation
Sortie invalide UTF-8
Tests unitaires obligatoires
Les tests doivent créer leurs propres faux exécutables temporaires.
Ils ne doivent pas dépendre de :
Ils peuvent utiliser des scripts temporaires avec un shebang, car le projet cible Linux.
Le code du module ne doit cependant jamais lancer un shell explicitement.
1. Arguments invalides
Tester au minimum :
executable_path == NULL;out_result == NULL;*out_result != NULL;GErrordéjà initialisé si cette convention est vérifiée par le projet.Résultat attendu :
2. Exécution sans argument
Créer un faux outil qui affiche un texte fixe.
Vérifier :
TRUE;stderrvide ;is_success == TRUE.3. Transmission exacte des arguments
Le faux outil doit afficher chaque argument reçu sur une ligne séparée.
Tester des arguments comme :
Vérifier que les valeurs sont restituées littéralement.
Le test doit également vérifier qu’aucun fichier d’injection n’a été créé.
Ce test prouve qu’aucun shell n’interprète les arguments.
4. Capture séparée de stdout et stderr
Le faux outil écrit :
dans
stdout, et :dans
stderr.Vérifier que les deux sorties ne sont pas mélangées.
5. Code de sortie non nul
Le faux outil doit :
Vérifier :
tool_process_run() == TRUE;7;is_success == FALSE.6. Exécutable inexistant
Utiliser un chemin temporaire inexistant.
Vérifier :
FALSE;NULL;TOOL_PROCESS_ERROR_SPAWN.7. Dossier de travail
Créer un dossier temporaire et un outil affichant son répertoire courant.
Exécuter avec
working_directory.Vérifier que la sortie correspond au chemin demandé.
8. Annulation avant le lancement
Créer un
GCancellable, l’annuler avant l’appel, puis exécuter le faux outil.Vérifier :
FALSE;NULL;TOOL_PROCESS_ERROR_CANCELLED.9. Annulation pendant l’exécution
Créer un faux outil long, par exemple :
Lancer l’annulation depuis un second thread après un court délai.
Vérifier :
FALSE;Le test ne doit pas dépendre d’une boucle principale GTK.
10. Sortie vide
Créer un outil qui ne produit aucune sortie.
Vérifier que les accesseurs de sortie restent sûrs.
11. Octets non UTF-8
Créer un outil qui écrit au moins un octet non UTF-8 dans
stdout.Vérifier :
TRUE;GBytes;Ce test confirme que le module n’utilise pas une API limitée au texte UTF-8.
12. Terminaison par signal
Sur Linux, créer un faux outil qui se termine lui-même par un signal.
Vérifier lorsque la plateforme le permet :
exited_normally == FALSE;was_signaled == TRUE;exit_status == -1;is_success == FALSE.Le test peut être conditionné avec les macros de plateforme appropriées.
Noms de tests suggérés
Fixtures de test
Une fixture peut contenir :
Le
setupdoit :Le
teardowndoit :Chaque test doit rester isolé.
Makefile
Ajouter :
Règle attendue :
Ajouter la cible dans :
et dans :
TEST_LDFLAGScontient déjàgio-2.0, nécessaire pourGSubprocess.Vérifications manuelles
Aucun avertissement de compilation ne doit être accepté.
Vérification mémoire
Exécuter :
Vérifier particulièrement les chemins :
Vérification des processus enfants
Pendant le test d’annulation, contrôler si nécessaire qu’aucun faux outil ne reste actif après la fin du test.
Le module ne doit créer ni zombie ni processus abandonné.
Critères d’acceptation
Le ticket est validé lorsque :
GSubprocessouGSubprocessLauncher;stdoutetstderrsont capturés séparément ;GBytes;make testetmake clean.Exemple d’utilisation attendu
L’exemple illustre le comportement attendu. Il ne constitue pas une obligation d’organisation interne.
Intégration future
Après validation de ce ticket :
BackgroundTaskexécutantToolProcess;