Partager via


PreviousMode

Lorsqu’une application en mode utilisateur appelle la version Nt ou Zw d’une routine de services système natifs, le mécanisme d’appel système intercepte le thread appelant en mode noyau. Pour indiquer que les valeurs de paramètre proviennent du mode utilisateur, le gestionnaire d’interruptions pour l’appel système définit le champ PreviousMode dans l’objet thread de l’appelant sur UserMode. La routine des services système natifs vérifie le champ PreviousMode du thread appelant pour déterminer si les paramètres proviennent d’une source en mode utilisateur.

Si un pilote en mode noyau appelle une routine de services système natives et passe des valeurs de paramètres à la routine provenant d’une source en mode noyau, le pilote doit s’assurer que le champ PreviousMode dans l’objet thread actuel est défini sur KernelMode.

Un pilote en mode noyau peut s’exécuter dans le contexte d’un thread arbitraire, et le champ PreviousMode de ce thread peut être défini sur UserMode. Dans ce cas, un pilote en mode noyau peut appeler la version Zw d’une routine de services système natifs pour informer la routine que les valeurs de paramètre proviennent d’une source approuvée en mode noyau. L’appel Zw va à une fonction wrapper mince qui remplace la valeur PreviousMode dans l’objet thread actuel. La fonction wrapper définit PreviousMode sur KernelMode et appelle la version Nt de la routine. Au retour de la version Nt de la routine, la fonction wrapper restaure la valeur PreviousMode d’origine de l’objet thread et retourne.

Un pilote en mode noyau peut appeler directement la version Nt d’une routine de services système natifs. Lorsqu’un pilote en mode noyau traite une demande d’E/S qui peut provenir du mode utilisateur ou du mode noyau, le pilote peut appeler la version Nt de la routine afin que la valeur PreviousMode du thread actuel reste inchangée pendant l’appel. La routine NtXxx vérifie la valeur PreviousMode du thread appelant pour déterminer si les valeurs de paramètre proviennent d’une application en mode utilisateur ou d’un composant en mode noyau, et les traite en conséquence.

Une erreur peut se produire si un pilote en mode noyau appelle une routine NtXxx et que la valeur PreviousMode dans l’objet thread actuel n’indique pas avec précision si les valeurs de paramètre proviennent d’une source en mode utilisateur ou en mode noyau.

Par exemple, supposons qu’un pilote en mode noyau s’exécute dans le contexte d’un thread arbitraire et que la valeur PreviousMode de ce thread est définie sur UserMode. Si le pilote transmet un handle de fichier en mode noyau à la routine NtClose , cette routine vérifie la valeur PreviousMode et décide que le handle doit être un handle en mode utilisateur. Lorsque NtClose ne trouve pas le handle dans la table de handle en mode utilisateur, il retourne le code d’erreur STATUS_INVALID_HANDLE. Pendant ce temps, le pilote fait fuiter le handle en mode noyau, qui n’a jamais été fermé.

Par exemple, si les paramètres d’une routine NtXxx incluent une mémoire tampon d’entrée ou de sortie, et si PreviousMode = UserMode, la routine appelle la routine ProbeForRead ou ProbeForWrite pour valider la mémoire tampon. Si la mémoire tampon a été allouée dans la mémoire système plutôt que dans la mémoire en mode utilisateur, la routine ProbeForXxx déclenche une exception et la routine NtXxx retourne le code d’erreur STATUS_ACCESS_VIOLATION.

Si nécessaire, un pilote peut appeler la routine ExGetPreviousMode pour obtenir la valeur PreviousMode à partir de l’objet thread actuel. Ou bien, le pilote peut lire le champ RequestorMode à partir de la structure IRP qui décrit l’opération d’E/S demandée. Le champ RequestorMode contient une copie de la valeur PreviousMode du thread qui a demandé l’opération.