\nocite{keetch2009practicalsandboxing} \nocite{ISCWindowsACL} \nocite{GoogleProjectZero} % TODO: remplacer confiant Après la présentation des objectifs liés aux communications inter-processus et à l'implémentation Linux, nous pouvons essayer de reprendre le même modèle pour l'implémentation Windows. Malheureusement celle-ci vient nous rappeler qu'un changement de système implique parfois un changement de paradigme. La documentation quelque peu hasardeuse va néanmoins nous permettre de mettre en place une architecture similaire. \section{Communication inter-processus} Windows dispose de beaucoup de moyens de communication inter-processus. Parmi ceux là, aucun ne va avoir les mêmes propriétés que les sockets Unix. Nous allons même de base éliminer tous les moyens \og{}haut niveau\fg{} comme les ports COM résolvant plutôt des problèmes d'interopérabilité et se concentrer sur les moyens plus bas niveau. \subsection{Les sockets Windows} Les sockets Windows réimplémentent la même interface que les sockets Berkeley mais ne fournissent pas de sockets locaux ou anonymes. Ceux-ci passent par la pile réseau pour l'envoi de message. On notera cependant l'implémentation de \og{}TCP Loopback Fast Path\fg{} depuis Windows Server 2012. Cette fonctionnalité conserve la sémantique du protocole TCP tout en désactivant des fonctionnalités comme l'algorithme de Nagle. \cite{WindowsFastTCPLoopback} C'est donc ce qui ressemble le plus aux sockets Unix, excepté l'accès au réseau et le passage de descripteur de fichiers. \subsection{Les canaux anonymes} Les canaux anonymes donnent un moyen de communication unidirectionnel avec un écrivain et un lecteur. Il faut donc utiliser une paire de canaux anonymes pour pouvoir discuter en full-duplex, mais également utiliser un mécanisme pour transmettre le \inltype{HANDLE} d'un processus à l'autre. À noter que la plupart des fonctions sur les canaux nommés fonctionnent avec les canaux anonymes, ces derniers étant implémentés comme des canaux nommés avec un nom particulier. \subsection{Les canaux nommés} Les canaux nommés sont capables de fonctionner en full-duplex et disposent pleinement du système d'ACL global de Windows. Ici, on va plutôt s'intéresser aux canaux nommés et voir comment on peut les utiliser pour transmettre des messages et des ressources. La création d'un canal nommé se fait avec avec la famille de fonction \inltype{CreateNamedPipe}. Dans notre cas, on sera fortement tenté d'utiliser des \inltype{lpSecurityAttributes} définis avec de bonnes valeurs, mais ce point sera exploré dans la suite du document. \begin{code}{c}{Prototype de \inltype{CreateNamedPipe}} HANDLE CreateNamedPipeA( LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes ); \end{code} \section{Transfert de ressources entre processus} Windows dispose de trois mécanismes pour partager des ressources entre processus. Les ressources sont représentées par des objets \inltype{HANDLE}. La première méthode est l'héritage, qui a lieu lors de la création d'un nouveau processus. Les descripteurs de fichiers marqués comme héritables, ou bien aucun si \inltype{bInheritHandles} est précisé à \inltype{FALSE} lors de l'appel de \inltype{CreateProcess}, seront récupérés dans le nouveau processus avec la même valeur. Lorsqu'un \inltype{HANDLE} est hérité, il garde la même valeur dans le nouveau processus et il faut donc le transmettre soit par IPC, soit par paramètre de la ligne de commande, soit par injection de code dans le nouveau processus. La seconde méthode utilise la fonction \inltype{DuplicateHandle} pour injecter le descripteur de fichier dans le nouveau processus. Dans ce cas-là, si l'appel est fait depuis le processus parent, une nouvelle valeur est générée pour ce \inltype{HANDLE} et il faut le transmettre au processus enfant par l'une des méthodes mentionnées dans le cas de l'héritage. \begin{code}{c}{Prototype de la fonction \inltype{DuplicateHandle}} BOOL WINAPI DuplicateHandle( _In_ HANDLE hSourceProcessHandle, _In_ HANDLE hSourceHandle, _In_ HANDLE hTargetProcessHandle, _Out_ LPHANDLE lpTargetHandle, _In_ DWORD dwDesiredAccess, _In_ BOOL bInheritHandle, _In_ DWORD dwOptions ); \end{code} L'exploitation de \inltype{DuplicateHandle} demande à ce que chacun des deux processus rentrant en jeu dans la fonction, à savoir \inltype{hSourceProcessHandle} et \inltype{hTargetProcessHandle} disposent du droit \inltype{PROCESS_DUP_HANDLE}. Étant donné que la fonction peut être utilisée de la source vers la destination ou depuis la destination récupérant un \inltype{HANDLE} appartenant à la source, le processus ayant accès à l'autre processus est capable de copier tout accès existant et dispose donc des mêmes droits que ce dernier. Cette remarque est importante pour se rendre compte que l'utilisation de cette méthode implique nécessairement un broker, qui sera suffisamment privilégié pour accéder aux deux processus souhaitant partager une ressource. Tenter d'appliquer cette fonction directement dans les workers impliquerait que chacun des workers auraient les mêmes droits que ses voisin et, de façon transitive, aurait accès à toutes les zones de privilèges connexes dans le graphe d'IPC. Enfin, la troisième méthode consiste à utiliser les objets nommés qui sont créés d'un côté par le processus parent, puis ouverts par les processus enfants en les référençant par leur nom. Dans le prototype, j'ai utilisé des canaux nommés pour faciliter la mise en place mais j'ai également essayé d'utiliser des paires de canaux anonymes dans d'autres codes simulant le fonctionnement des IPC. J'ai également prévu de mettre en place la méthode utilisant \inltype{DuplicateHandle} et donc un broker central pour pouvoir transférer des ressources de la même façon que sous Linux. J'essayerai cependant de m'approcher d'un modèle orchestrateur avec d'autres techniques mais nous allons voir qu'il n'y a pas vraiment d'alternative pour l'instant.