Définition de codes de contrôle d’E/S
Lors de la définition de nouvelles listes IOCTL, il est important de mémoriser les règles suivantes :
- Si un nouveau IOCTL est disponible pour les composants logiciels en mode utilisateur, le IOCTL doit être utilisé avec IRP_MJ_DEVICE_CONTROL demandes. Les composants en mode utilisateur envoient IRP_MJ_DEVICE_CONTROL requêtes en appelant deviceIoControl, qui est une fonction Win32.
- Si un nouveau IOCTL est disponible uniquement pour les composants du pilote en mode noyau, le IOCTL doit être utilisé avec IRP_MJ_INTERNAL_DEVICE_CONTROL demandes. Les composants en mode noyau créent des requêtes IRP_MJ_INTERNAL_DEVICE_CONTROL en appelant IoBuildDeviceIoControlRequest. Pour plus d’informations, consultez Création de demandes IOCTL dans les pilotes.
Un code de contrôle d’E/S est une valeur 32 bits qui se compose de plusieurs champs. La figure suivante illustre la disposition des codes de contrôle d’E/S.
Utilisez la macro CTL_CODE fournie par le système, qui est définie dans Wdm.h et Ntddk.h, pour définir de nouveaux codes de contrôle d’E/S. La définition d’un nouveau code IOCTL, qu’il soit destiné à être utilisé avec des requêtes IRP_MJ_DEVICE_CONTROL ou IRP_MJ_INTERNAL_DEVICE_CONTROL , utilise le format suivant :
#define IOCTL_Device_Function CTL_CODE(DeviceType, Function, Method, Access)
Choisissez un nom de constante descriptif pour le IOCTL, sous la forme IOCTL_Device_Function, où Device indique le type d’appareil et Function indique l’opération. Un exemple de nom de constante est IOCTL_VIDEO_ENABLE_CURSOR.
Fournissez les paramètres suivants à la macro CTL_CODE :
DeviceType
Identifie le type d’appareil. Cette valeur doit correspondre à la valeur définie dans le membre DeviceType de la structure DEVICE_OBJECT du pilote. (Voir Spécification des types d’appareils). Les valeurs inférieures à 0x8000 sont réservées à Microsoft. Les valeurs de 0x8000 et supérieures peuvent être utilisées par les fournisseurs. Notez que les valeurs attribuées par le fournisseur définissent le bit commun .
FunctionCode
Identifie la fonction à effectuer par le pilote. Les valeurs inférieures à 0x800 sont réservées à Microsoft. Les valeurs de 0x800 et supérieures peuvent être utilisées par les fournisseurs. Notez que les valeurs attribuées par le fournisseur définissent le bit personnalisé .
TransferType
Indique comment le système transmet les données entre l’appelant de DeviceIoControl (ou IoBuildDeviceIoControlRequest) et le pilote qui gère l’IRP.
Utilisez l’une des constantes définies par le système suivantes :
METHOD_BUFFERED
Spécifie la méthode d’E/S mise en mémoire tampon , qui est généralement utilisée pour transférer de petites quantités de données par requête. La plupart des codes de contrôle d’E/S pour les pilotes d’appareil et intermédiaires utilisent cette valeur TransferType .
Pour plus d’informations sur la façon dont le système spécifie des mémoires tampons de données pour les codes de contrôle d’E/S METHOD_BUFFERED, consultez Descriptions des tampons pour les codes de contrôle d’E/S.
Pour plus d’informations sur les E/S mises en mémoire tampon, consultez Utilisation des E/S mises en mémoire tampon.
METHOD_IN_DIRECT ou METHOD_OUT_DIRECT
Spécifie la méthode d’E/S directe , qui est généralement utilisée pour lire ou écrire de grandes quantités de données, à l’aide de DMA ou de PIO, qui doit être transférée rapidement.
Spécifiez METHOD_IN_DIRECT si l’appelant de DeviceIoControl ou IoBuildDeviceIoControlRequest transmet des données au pilote.
Spécifiez METHOD_OUT_DIRECT si l’appelant de DeviceIoControl ou d’IoBuildDeviceIoControlRequest recevra des données du pilote.
Pour plus d’informations sur la façon dont le système spécifie les mémoires tampons de données pour les codes de contrôle d’E/S METHOD_IN_DIRECT et METHOD_OUT_DIRECT, consultez Descriptions de la mémoire tampon pour les codes de contrôle d’E/S.
Pour plus d’informations sur les E/S directes, consultez Utilisation des E/S directes.
METHOD_NEITHER
Ne spécifie ni e/S mises en mémoire tampon ni E/S directes. Le gestionnaire d’E/S ne fournit pas de mémoires tampons système ni de DLL MDL. L’IRP fournit les adresses virtuelles en mode utilisateur des mémoires tampons d’entrée et de sortie qui ont été spécifiées sur DeviceIoControl ou IoBuildDeviceIoControlRequest, sans les valider ni les mapper.
Pour plus d’informations sur la façon dont le système spécifie les mémoires tampons de données pour les codes de contrôle d’E/S METHOD_NEITHER, consultez Descriptions des tampons pour les codes de contrôle d’E/S.
Cette méthode ne peut être utilisée que si l’exécution du pilote peut être garantie dans le contexte du thread à l’origine de la demande de contrôle d’E/S. Seul un pilote en mode noyau de niveau supérieur est garanti pour répondre à cette condition, de sorte que METHOD_NEITHER est rarement utilisé pour les codes de contrôle d’E/S qui sont passés aux pilotes de périphérique de bas niveau.
Avec cette méthode, le pilote de niveau supérieur doit déterminer s’il faut configurer un accès en mémoire tampon ou direct aux données utilisateur à la réception de la demande, doit éventuellement verrouiller la mémoire tampon utilisateur et doit encapsuler son accès à la mémoire tampon utilisateur dans un gestionnaire d’exceptions structuré (voir Gestion des exceptions). Sinon, l’appelant en mode utilisateur d’origine peut modifier les données mises en mémoire tampon avant que le pilote ne puisse les utiliser, ou l’appelant peut être échangé au fur et à mesure que le pilote accède à la mémoire tampon utilisateur.
Pour plus d’informations, consultez Utilisation des E/S directes ou mises en mémoire tampon.
RequiredAccess
Indique le type d’accès qu’un appelant doit demander lors de l’ouverture de l’objet fichier qui représente l’appareil (voir IRP_MJ_CREATE). Le gestionnaire d’E/S crée des irps et appelle le pilote avec un code de contrôle d’E/S particulier uniquement si l’appelant a demandé les droits d’accès spécifiés.
RequiredAccess est spécifié à l’aide des constantes définies par le système suivantes :
FILE_ANY_ACCESS
Le gestionnaire d’E/S envoie l’IRP pour tout appelant disposant d’un handle à l’objet de fichier qui représente l’objet d’appareil cible.
FILE_READ_DATA
Le gestionnaire d’E/S envoie l’IRP uniquement pour un appelant disposant de droits d’accès en lecture, ce qui permet au pilote de périphérique sous-jacent de transférer des données de l’appareil vers la mémoire système.
FILE_WRITE_DATA
Le gestionnaire d’E/S envoie l’IRP uniquement pour un appelant disposant de droits d’accès en écriture, ce qui permet au pilote de périphérique sous-jacent de transférer des données de la mémoire système vers son appareil.
FILE_READ_DATA et FILE_WRITE_DATA peuvent être ORed ensemble si l’appelant doit disposer de droits d’accès en lecture et en écriture.
Certains codes de contrôle d’E/S définis par le système ont une valeur RequiredAccess de FILE_ANY_ACCESS, ce qui permet à l’appelant d’envoyer le IOCTL particulier, quel que soit l’accès accordé à l’appareil. Les exemples incluent les codes de contrôle d’E/S qui sont envoyés aux pilotes d’appareils exclusifs.
D’autres codes de contrôle d’E/S définis par le système exigent que l’appelant dispose de droits d’accès en lecture, de droits d’accès en écriture ou les deux. Par exemple, la définition suivante du code de contrôle d’E/S public IOCTL_DISK_SET_PARTITION_INFO indique que cette demande d’E/S ne peut être envoyée à un pilote que si l’appelant dispose des droits d’accès en lecture et en écriture :
#define IOCTL_DISK_SET_PARTITION_INFO\
CTL_CODE(IOCTL_DISK_BASE, 0x008, METHOD_BUFFERED,\
FILE_READ_DATA | FILE_WRITE_DATA)
Notes
Avant de spécifier FILE_ANY_ACCESS pour un nouveau code IOCTL, vous devez être absolument certain que l’autorisation d’un accès illimité à votre appareil ne crée pas un chemin d’accès possible pour les utilisateurs malveillants afin de compromettre le système.
Les pilotes peuvent utiliser IoValidateDeviceIoControlAccess pour effectuer une vérification d’accès plus stricte que celle fournie par les bits RequiredAccess d’un IOCTL.
Autres macros utiles
Les macros suivantes sont utiles pour extraire les champs DeviceType 16 bits et TransferType 2 bits d’un code IOCTL :
#define DEVICE_TYPE_FROM_CTL_CODE(ctrlCode) (((ULONG)(ctrlCode & 0xffff0000)) >> 16)
#define METHOD_FROM_CTL_CODE(ctrlCode) ((ULONG)(ctrlCode & 3))
Ces macros sont définies dans Wdm.h et Ntddk.h.