En informática , ioctl
(abreviatura de control de entrada/salida ) es una llamada al sistema para operaciones de entrada/salida específicas del dispositivo y otras operaciones que no se pueden expresar mediante la semántica de archivo normal. Toma un parámetro que especifica un código de solicitud; el efecto de una llamada depende completamente del código de solicitud. Los códigos de solicitud suelen ser específicos del dispositivo. Por ejemplo, un controlador de dispositivo de CD-ROM que puede indicar a un dispositivo físico que expulse un disco proporcionaría un ioctl
código de solicitud para hacerlo. Los códigos de solicitud independientes del dispositivo a veces se utilizan para dar acceso de espacio de usuario a funciones del núcleo que solo se utilizan por el software del sistema central o que aún están en desarrollo.
La ioctl
llamada al sistema apareció por primera vez en la versión 7 de Unix con ese nombre. Es compatible con la mayoría de los sistemas Unix y similares , incluidos Linux y macOS , aunque los códigos de solicitud disponibles difieren de un sistema a otro. Microsoft Windows proporciona una función similar, denominada " DeviceIoControl
", en su API Win32 .
Los sistemas operativos convencionales se pueden dividir en dos capas: el espacio de usuario y el núcleo . El código de aplicación, como un editor de texto, reside en el espacio de usuario, mientras que las funciones subyacentes del sistema operativo, como la pila de red , residen en el núcleo. El código del núcleo maneja recursos confidenciales e implementa las barreras de seguridad y confiabilidad entre aplicaciones; por esta razón, el sistema operativo impide que las aplicaciones en modo usuario accedan directamente a los recursos del núcleo.
Las aplicaciones del espacio de usuario suelen realizar solicitudes al núcleo mediante llamadas al sistema , cuyo código se encuentra en la capa del núcleo. Una llamada al sistema suele adoptar la forma de un "vector de llamada al sistema", en el que la llamada al sistema deseada se indica con un número de índice. Por ejemplo, exit()
podría ser la llamada al sistema número 1 y write()
la número 4. El vector de llamada al sistema se utiliza entonces para encontrar la función del núcleo deseada para la solicitud. De esta forma, los sistemas operativos convencionales suelen proporcionar varios cientos de llamadas al sistema al espacio de usuario.
Aunque se trata de un diseño conveniente para acceder a las funciones estándar del núcleo, las llamadas al sistema a veces no son adecuadas para acceder a periféricos de hardware no estándar. Por necesidad, la mayoría de los periféricos de hardware (también conocidos como dispositivos) solo se pueden direccionar directamente dentro del núcleo. Pero es posible que el código de usuario deba comunicarse directamente con los dispositivos; por ejemplo, un administrador puede configurar el tipo de medio en una interfaz Ethernet . Los sistemas operativos modernos admiten diversos dispositivos, muchos de los cuales ofrecen una gran variedad de funciones. Es posible que el diseñador del núcleo no haya previsto algunas de estas funciones y, en consecuencia, es difícil que un núcleo proporcione llamadas al sistema para utilizar los dispositivos.
Para resolver este problema, el núcleo está diseñado para ser extensible y puede aceptar un módulo adicional llamado controlador de dispositivo que se ejecuta en el espacio del núcleo y puede dirigirse directamente al dispositivo. Una ioctl
interfaz es una única llamada al sistema mediante la cual el espacio de usuario puede comunicarse con los controladores de dispositivo. Las solicitudes a un controlador de dispositivo se dirigen con respecto a esta ioctl
llamada al sistema, normalmente mediante un identificador del dispositivo y un número de solicitud. De este modo, el núcleo básico puede permitir que el espacio de usuario acceda a un controlador de dispositivo sin saber nada acerca de las funciones admitidas por el dispositivo y sin necesidad de una colección de llamadas al sistema inmanejablemente grande.
Un uso común ioctl
es controlar dispositivos de hardware.
Por ejemplo, en sistemas Win32ioctl
, las llamadas pueden comunicarse con dispositivos USB o pueden descubrir información sobre la geometría de la unidad de los dispositivos de almacenamiento conectados.
En OpenBSD y NetBSD , ioctl
es utilizado por el bio(4)
controlador de pseudodispositivo y la bioctl
utilidad para implementar la administración de volumen RAID en una interfaz unificada e independiente del proveedor similar a ifconfig
. [1] [2]
En NetBSD , ioctl
también lo utiliza el sysmon
framework. [3]
Un uso del ioctl
código expuesto a las aplicaciones del usuario final es la E/S de terminal.
Los sistemas operativos Unix han hecho tradicionalmente un uso intensivo de las interfaces de línea de comandos , originalmente con terminales de texto de hardware como los VT100 conectados a puertos serie , y más tarde con emuladores de terminal y servidores de inicio de sesión remotos que utilizan pseudoterminales . Los dispositivos de puerto serie y los pseudoterminales se controlan y configuran mediante ioctl
llamadas. Por ejemplo, el tamaño de la pantalla se establece mediante la TIOCSWINSZ
llamada. La función ioctl TIOCSTI (control de E/S de terminal, simulación de entrada de terminal) puede insertar un carácter en un flujo de dispositivo. [4]
Cuando las aplicaciones necesitan extender el núcleo, por ejemplo para acelerar el procesamiento de la red, ioctl
las llamadas proporcionan una manera conveniente de conectar el código del espacio de usuario con las extensiones del núcleo. Las extensiones del núcleo pueden proporcionar una ubicación en el sistema de archivos que se puede abrir por nombre, a través de la cual ioctl
se puede enviar una cantidad arbitraria de llamadas, lo que permite programar la extensión sin agregar llamadas del sistema al sistema operativo.
Según un desarrollador de OpenBSD , ioctl
y sysctl
son las dos llamadas del sistema para extender el kernel, sysctl
siendo posiblemente la más simple de las dos. [5]
En NetBSD , el sysmon_envsys
marco para la monitorización de hardware utiliza ioctl
a través de proplib
; mientras que OpenBSD y DragonFly BSD en cambio utilizan sysctl
para su hw.sensors
marco correspondiente. La revisión original de envsys
en NetBSD se implementó con ioctl
antes de proplib
que estuviera disponible, y tenía un mensaje que sugería que el marco es experimental y debería ser reemplazado por una sysctl(8)
interfaz, en caso de que se desarrollara una, [6] [7] lo que potencialmente explica la elección de sysctl
en OpenBSD con su posterior introducción de hw.sensors
en 2003. Sin embargo, cuando el envsys
marco fue rediseñado en 2007 alrededor de proplib
, la llamada al sistema permaneció como ioctl
y el mensaje fue eliminado. [8]
La ioctl
llamada al sistema apareció por primera vez en la versión 7 de Unix , como reemplazo de las llamadas al sistema stty
[9] y gtty
, con un argumento de código de solicitud adicional. Una ioctl
llamada toma como parámetros :
El núcleo generalmente envía una ioctl
llamada directamente al controlador del dispositivo, que puede interpretar el número de solicitud y los datos de la forma que se requiera. Los autores de cada controlador documentan los números de solicitud para ese controlador en particular y los proporcionan como constantes en un archivo de encabezado .
Los números de solicitud suelen combinar un código que identifica el dispositivo o la clase de dispositivos a los que se dirige la solicitud y un número que indica la solicitud en particular; el código que identifica el dispositivo o la clase de dispositivos suele ser un único carácter ASCII. Algunos sistemas Unix, incluidos 4.2BSD y versiones posteriores de BSD , sistemas operativos derivados de esas versiones y Linux , tienen convenciones que también codifican dentro del número de solicitud el tamaño de los datos que se transferirán hacia/desde el controlador del dispositivo y la dirección de la transferencia de datos. Independientemente de si se siguen dichas convenciones, el núcleo y el controlador colaboran para entregar un código de error uniforme (indicado por la constante simbólica ENOTTY
) a una aplicación que realiza una solicitud a un controlador que no lo reconoce.
El mnemónico ENOTTY
(tradicionalmente asociado con el mensaje de texto " No es una máquina de escribir ") proviene de los primeros sistemas que incorporaban una ioctl
llamada, donde solo el dispositivo de teletipo ( tty
) generaba este error. Aunque el mnemónico simbólico está fijado por requisitos de compatibilidad, algunos sistemas modernos muestran de manera más útil un mensaje más general como " Operación de control de dispositivo inapropiada " (o una localización del mismo).
TCSETS
ejemplifica una ioctl
llamada en un puerto serial . Las llamadas normales de lectura y escritura en un puerto serial reciben y envían bytes de datos. Una ioctl(fd,TCSETS,data)
llamada, separada de dicha E/S normal, controla varias opciones del controlador, como el manejo de caracteres especiales o las señales de salida en el puerto (como la señal DTR ).
Un Win32 DeviceIoControl
toma como parámetros:
OVERLAPPED
estructura, si se utiliza E/S superpuesta .El código de control del dispositivo Win32 tiene en cuenta el modo de operación que se está realizando.
Hay 4 modos de operación definidos que afectan la seguridad del controlador del dispositivo:
METHOD_IN_DIRECT
:Se verifica que la dirección del búfer sea legible para el llamador del modo usuario.METHOD_OUT_DIRECT
:El llamador del modo usuario verifica que la dirección del búfer pueda escribirse.METHOD_NEITHER
:Las direcciones virtuales del modo de usuario se pasan al controlador sin asignación ni validación.METHOD_BUFFERED
Los buffers compartidos controlados por IO Manager se utilizan para mover datos hacia y desde el modo de usuario.Los dispositivos y las extensiones del kernel se pueden vincular al espacio de usuario mediante nuevas llamadas de sistema adicionales, aunque este enfoque rara vez se adopta porque los desarrolladores de sistemas operativos intentan mantener la interfaz de llamadas del sistema enfocada y eficiente.
En los sistemas operativos Unix, otras dos interfaces de llamadas vectoriales son populares: la fcntl
llamada del sistema ("control de archivos") configura archivos abiertos y se utiliza en situaciones tales como habilitar E/S sin bloqueo ; y la setsockopt
llamada del sistema ("establecer opción de socket") configura sockets de red abiertos , una función utilizada para configurar el ipfw
firewall de paquetes en sistemas Unix BSD .
ioctl
llamada, pero luego usan llamadas del sistema de mapeo de memoria para vincular una parte de su espacio de direcciones al del núcleo. Esta interfaz es una forma mucho más eficiente de proporcionar transferencia de datos en masa entre un dispositivo y una aplicación de espacio de usuario; ioctl
las llamadas del sistema individuales o de lectura/escritura generan sobrecarga debido a las transiciones repetidas del espacio de usuario al núcleo, donde el acceso a un rango de direcciones mapeadas en memoria no genera dicha sobrecarga.DeviceIoControl METHOD_
accesos estándar son suficientes.Netlink es un mecanismo tipo socket para la comunicación entre procesos (IPC), diseñado para ser un sucesor más flexible de ioctl
.
ioctl
Las llamadas minimizan la complejidad de la interfaz de llamadas del sistema del núcleo. Sin embargo, al proporcionar un lugar para que los desarrolladores "guarden" fragmentos de las interfaces de programación del núcleo, ioctl
las llamadas complican la API general de usuario a núcleo. Un núcleo que proporciona varios cientos de llamadas del sistema puede proporcionar varios miles de llamadas ioctl.
Aunque la interfaz de ioctl
las llamadas parece algo diferente de las llamadas al sistema convencionales, en la práctica hay poca diferencia entre una ioctl
llamada y una llamada al sistema; una ioctl
llamada es simplemente una llamada al sistema con un mecanismo de despacho diferente. Por lo tanto, muchos de los argumentos en contra de la expansión de la interfaz de llamadas al sistema del núcleo se podrían aplicar a ioctl
las interfaces.
Para los desarrolladores de aplicaciones, las llamadas al sistema no se diferencian en nada de las subrutinas de la aplicación; son simplemente llamadas a funciones que toman argumentos y devuelven valores. Las bibliotecas de tiempo de ejecución del sistema operativo ocultan la complejidad que implica invocar llamadas al sistema. Desafortunadamente, las bibliotecas de tiempo de ejecución no hacen que ioctl
las llamadas sean tan transparentes. Las operaciones simples, como descubrir las direcciones IP de una máquina, a menudo requieren una maraña de ioctl
llamadas, cada una de las cuales requiere números mágicos y estructuras de argumentos. [ cita requerida ]
Libpcap y libdnet son dos ejemplos de bibliotecas Unix de terceros diseñadas para enmascarar la complejidad de ioctl
las interfaces, para la captura de paquetes y la E/S de paquetes, respectivamente.
Las interfaces de usuario a núcleo de los sistemas operativos principales suelen ser objeto de auditorías exhaustivas para detectar fallos de código y vulnerabilidades de seguridad antes de su lanzamiento. Estas auditorías suelen centrarse en las interfaces de llamadas del sistema bien documentadas; por ejemplo, los auditores pueden asegurarse de que las llamadas de seguridad sensibles, como el cambio de ID de usuario, solo estén disponibles para los usuarios administrativos.
ioctl
Las interfaces son más complicadas, más diversas y, por lo tanto, más difíciles de auditar que las llamadas del sistema. Además, dado que ioctl
las llamadas pueden ser proporcionadas por desarrolladores externos, a menudo después de que se haya lanzado el sistema operativo principal, ioctl
las implementaciones de llamadas pueden recibir menos escrutinio y, por lo tanto, albergar más vulnerabilidades. Por último, muchas ioctl
llamadas, en particular para controladores de dispositivos de terceros, no están documentadas.
Dado que el controlador de una ioctl
llamada reside directamente en el modo kernel, la entrada del espacio de usuario debe validarse cuidadosamente. Los usuarios locales pueden aprovechar las vulnerabilidades en los controladores de dispositivos al pasar búferes no válidos a ioctl
las llamadas.
Los sistemas operativos Win32 y Unix pueden proteger el nombre de un dispositivo de espacio de usuario del acceso por parte de aplicaciones con controles de acceso específicos aplicados al dispositivo. Pueden surgir problemas de seguridad cuando los desarrolladores de controladores de dispositivos no aplican controles de acceso adecuados al objeto accesible del espacio de usuario.
Algunos sistemas operativos modernos protegen el núcleo del código hostil del espacio de usuario (como aplicaciones que han sido infectadas por vulnerabilidades de desbordamiento de búfer ) mediante envoltorios de llamadas del sistema. Los envoltorios de llamadas del sistema implementan un control de acceso basado en roles al especificar qué llamadas del sistema pueden ser invocadas por qué aplicaciones; los envoltorios pueden, por ejemplo, usarse para "revocar" el derecho de un programa de correo a generar otros programas. ioctl
Las interfaces complican los envoltorios de llamadas del sistema porque hay una gran cantidad de ellos, cada uno de los cuales toma diferentes argumentos, algunos de los cuales pueden ser requeridos por programas normales.
{{cite web}}
: CS1 maint: nombres numéricos: lista de autores ( enlace )Una interfaz ioctl(2) disponible a través de /dev/sysmon.
[...] TIOCSTI [...] significa 'control de E/S de terminal, simular entrada de terminal'. En los sistemas que implementan esta función, insertará un carácter en el flujo de su dispositivo para que la próxima vez que cualquier proceso lea desde ese dispositivo, obtenga el carácter que usted puso allí.
Hay dos llamadas al sistema que se pueden usar para agregar funcionalidad al núcleo (sin agregar otra llamada al sistema): ioctl(2) y sysctl(3). Se eligió esta última porque era muy simple implementar la nueva característica.
Esta API es experimental y puede quedar obsoleta en cualquier momento... Esta API completa debería ser reemplazada por una interfaz sysctl(8) o un mecanismo de eventos del núcleo, en caso de que se desarrolle uno.